package top.codingfly.cto51;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.text.UnicodeUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.serializer.SerializerFeature;
import top.codingfly.aliyun.util.AliyunDownloadUtils;
import top.codingfly.cto51.entity.official.*;
import top.codingfly.cto51.entity.self.Chapter;
import top.codingfly.cto51.entity.self.CourseInfo;
import top.codingfly.util.AesUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

public class Cto51Scrapy {

    public static String md5SignKey = "30A5996A2D60B859";
    public static String deviceNumber = "ETfK7ioVr1kUJ37gMtD7pM1QxDLn1OpQ6bihOmbmQLY=";
    public static String userId = "mbZBs/2S+u2Ggl0x5SiOgA==";

    static {
        userId = AesUtils.decryptFromString(userId, Mode.CBC, Padding.ZeroPadding, "codingfly0123456", "0123456codingfly");
        deviceNumber = AesUtils.decryptFromString(deviceNumber, Mode.CBC, Padding.ZeroPadding, "codingfly0123456", "0123456codingfly");
        System.out.println(userId);
        System.out.println(deviceNumber);
    }

    /**  获取视频列表  */
    public static void main(String[] args) throws InterruptedException, UnsupportedEncodingException {
//        Cto51Class cto51Class = new Cto51Class();
//        cto51Class.setLessonId("918574");
//        cto51Class.setModuleId(null);
//        cto51Class.setOrigType("3");
//        Cto51Response<Cto51CoursePlayAuth> cto51Response = getCto51CoursePlayAuth(cto51Class);
//        System.out.println(JSON.toJSONString(cto51Response));

//        Cto51Response<Cto51Course> cto51Response = getCourseList("34073");
//        System.out.println(JSON.toJSONString(cto51Response));

        System.out.println(pageSearch("越狱插件的开发", 1));

        CourseInfo courseInfo = getAllCourseList(34073);
        if (courseInfo!=null && courseInfo.getChapterList()!=null) {
            List<Chapter> chapterList = courseInfo.getChapterList();
            for (int i = 0; i < chapterList.size(); i++) {
                Chapter chapter = chapterList.get(i);
                Cto51Class cto51Class = new Cto51Class();
                cto51Class.setLessonId(chapter.getLessonId());
                cto51Class.setModuleId(null);
                cto51Class.setOrigType("3");
                Cto51Response<Cto51CoursePlayAuth> cto51Response = getCto51CoursePlayAuth(cto51Class);
                Cto51CoursePlayAuth coursePlayAuth = cto51Response.getResult();
                AliyunDownloadUtils.downloadAuthVideo(coursePlayAuth.getVodVideoId(), coursePlayAuth.getVodPlayAuth(), "D:\\cto51\\m3u8", "D:\\cto51\\"+courseInfo.getCourseTitle()+"\\");
            }
        }
//        getAppKey();
    }

    public static void downloadCourse(Integer courseId) throws InterruptedException {
        CourseInfo courseInfo = getAllCourseList(courseId);
        if (courseInfo!=null && courseInfo.getChapterList()!=null) {
            List<Chapter> chapterList = courseInfo.getChapterList();
            for (int i = 0; i < chapterList.size(); i++) {
                Chapter chapter = chapterList.get(i);
                Cto51Class cto51Class = new Cto51Class();
                cto51Class.setLessonId(chapter.getLessonId());
                cto51Class.setModuleId(null);
                cto51Class.setOrigType("3");
                Cto51Response<Cto51CoursePlayAuth> cto51Response = getCto51CoursePlayAuth(cto51Class);
                Cto51CoursePlayAuth coursePlayAuth = cto51Response.getResult();
                AliyunDownloadUtils.downloadAuthVideo(coursePlayAuth.getVodVideoId(), coursePlayAuth.getVodPlayAuth(), "D:\\cto51\\m3u8", "D:\\cto51\\"+courseInfo.getCourseTitle()+"\\");
            }
        }
    }
    /**
     * 获取课程列表
     */
    /**
    public static CourseInfo getCourseList(String courseId) {
        String currentSecond = getCurrentSecond();
        TreeMap treeMap = new TreeMap();
        treeMap.put("channel", "official");
        treeMap.put("courseId", courseId);
        treeMap.put("deviceNumber", deviceNumber); // 这个参数可以乱传，但是会提示该设备没有登录
        treeMap.put("devices", "Android");
        treeMap.put("do", "course");
        treeMap.put("m", "courseInfo");
        treeMap.put("origType", "3");
        treeMap.put("time", currentSecond);
        treeMap.put("userId", userId); // 这个参数可以乱传，但是访问第二个视频，会提示该用户没购买
        treeMap.put("ver", "4.3.2");
        String sign = Base64.encode(cto51Md5Sign(cto51Md5Sign(treeMapSortStr(treeMap) + cto51Md5Sign(md5SignKey))))
                .toLowerCase()
                .replaceAll("[+]", "-")
                .replaceAll("/", "_")
                .replaceAll("\\+", "-")
                .replaceAll("=", "");
        treeMap.put("sign", sign);
        String result = HttpUtil.post("https://edu.51cto.com/app.php", treeMap);
        result = UnicodeUtil.toString(result);
        Cto51Response<Cto51Course> cto51Response = JSON.parseObject(result, new TypeReference<Cto51Response<Cto51Course>>(){});
        if (cto51Response==null || new Integer(0).equals(cto51Response.getSuccess())==false) {
            return null;
        }
        Cto51Course cto51Course = cto51Response.getResult();
        CourseInfo courseInfo = new CourseInfo();
        courseInfo.setCourseId(cto51Course.getCourseId());
        courseInfo.setDesc(cto51Course.getDesc());
        courseInfo.setCourseTitle(cto51Course.getCourseTitle());
        courseInfo.setLessonNum(cto51Course.getLessonNum());
        List<Chapter> chapterList = new ArrayList();
        courseInfo.setChapterList(chapterList);
        Cto51Lesson cto51Lesson = cto51Course.getLessonList();
        if (cto51Lesson.getChapterList()==null || cto51Lesson.getChapterList().size()<1) {
            return courseInfo;
        }
        Integer pageTotal = cto51Lesson.getPageTotal();
        Integer pageSize = cto51Lesson.getPageSize();
        String origType = null;
        Cto51Chapter cto51Chapter = cto51Lesson.getChapterList().get(0);
        List<Cto51Class> classList = cto51Chapter.getClassList();
        for (Cto51Class cto51Class:classList) {
            Chapter chapter = new Chapter();
            chapter.setLessonTitle(cto51Class.getLessonTitle());
            chapter.setLessonDesc(cto51Class.getLessonDesc());
            chapter.setLessonId(cto51Class.getLessonId());
            chapter.setCourseId(cto51Class.getCourseId());
            chapter.setOrigType(cto51Class.getOrigType());
            chapter.setModuleId(cto51Class.getModuleId());
            origType = cto51Class.getOrigType();
            chapterList.add(chapter);
        }
        return courseInfo;
    }
     */

    public static Object pageSearch(String keyword, Integer pageIndex) throws UnsupportedEncodingException {
        TreeMap treeMap = new TreeMap();
        treeMap.put("do", "index");
        treeMap.put("m", "search-v2");
        treeMap.put("keyWord", URLEncoder.encode(keyword));
        treeMap.put("userId", userId); // 该接口不用校验登录，随便传
        treeMap.put("type", "1");
        treeMap.put("page", pageIndex+"");
        treeMap.put("distinctId", UUID.randomUUID().toString().replace("-",""));
        treeMap.put("requestTrain", "1");
        addCommonParamsAndSign(treeMap);
        System.out.println(JSON.toJSONString(treeMap, SerializerFeature.PrettyFormat));
        String result = HttpUtil.post("https://edu.51cto.com/app.php", treeMap);
        result = UnicodeUtil.toString(result);
        return result;
    }

    public static CourseInfo getAllCourseList(Integer courseId) {
        TreeMap treeMap = new TreeMap();
        treeMap.put("do", "course");
        treeMap.put("m", "lessionList");
        treeMap.put("userId", userId); // "12775616"); // 这个参数不可以乱传，访问有权限接口会抛错
        treeMap.put("courseId", courseId+"");
        treeMap.put("origType", "3"); // 取值一般等于3
        treeMap.put("tag", "2");
        treeMap.put("pageSize", "500");
        treeMap.put("page", "1");
        treeMap.put("deviceId", deviceNumber); // "84925de3f86f9930|00ee8c7a"); // 这个参数可以乱传，{"msg":"该帐号已在另一个设备上登录，如果不是您的操作，此帐号的密码已经泄漏，请尽快登录并修改密码。","success":-3,"result":""}
        addCommonParamsAndSign(treeMap);
        String result = HttpUtil.post("https://edu.51cto.com/app.php", treeMap);
        result = UnicodeUtil.toString(result);
        System.out.println(result);
        Cto51Response<Cto51Lesson> cto51Response = JSON.parseObject(result, new TypeReference<Cto51Response<Cto51Lesson>>(){});
        if (cto51Response==null || new Integer(0).equals(cto51Response.getSuccess())==false) {
            return null;
        }
        Cto51Lesson cto51Lesson = cto51Response.getResult();
        CourseInfo courseInfo = new CourseInfo();
        courseInfo.setCourseId(courseId);
        courseInfo.setLessonNum(cto51Lesson.getItemTotal());
        List<Chapter> chapterList = new ArrayList();
        courseInfo.setChapterList(chapterList);
        if (cto51Lesson.getChapterList()==null || cto51Lesson.getChapterList().size()<1) {
            return courseInfo;
        }
        Cto51Chapter cto51Chapter = cto51Lesson.getChapterList().get(0);
        courseInfo.setCourseTitle(cto51Chapter.getChapterName());
        List<Cto51Class> classList = cto51Chapter.getClassList();
        for (Cto51Class cto51Class:classList) {
            Chapter chapter = new Chapter();
            chapter.setLessonTitle(cto51Class.getLessonTitle());
            chapter.setLessonDesc(cto51Class.getLessonDesc());
            chapter.setLessonId(cto51Class.getLessonId());
            chapter.setCourseId(cto51Class.getCourseId());
            chapter.setOrigType(cto51Class.getOrigType());
            chapter.setModuleId(cto51Class.getModuleId());
            chapterList.add(chapter);
        }
        return courseInfo;
    }

    public static void addCommonParamsAndSign(TreeMap treeMap) {
        String currentSecond = getCurrentSecond();
        treeMap.put("ver", "4.3.2");
        treeMap.put("channel", "official");
        treeMap.put("devices", "Android");
        treeMap.put("time", currentSecond);
        treeMap.put("deviceNumber", deviceNumber); // "84925de3f86f9930|00ee8c7a"); // 这个参数可以乱传，{"msg":"该帐号已在另一个设备上登录，如果不是您的操作，此帐号的密码已经泄漏，请尽快登录并修改密码。","success":-3,"result":""}
        treeMap.put("sign", signTreeMap(treeMap));
    }

    public static String signTreeMap(TreeMap treeMap) {
        return Base64.encode(cto51Md5Sign(cto51Md5Sign(treeMapSortStr(treeMap) + cto51Md5Sign(md5SignKey))))
                .toLowerCase()
                .replaceAll("[+]", "-")
                .replaceAll("/", "_")
                .replaceAll("\\+", "-")
                .replaceAll("=", "");
    }

    public static Cto51Response<Cto51CoursePlayAuth> getCto51CoursePlayAuth(Cto51Class cto51Class) {
        TreeMap treeMap = new TreeMap<>();
        treeMap.put("do", "course");
        treeMap.put("m", "videoNew");
        treeMap.put("ver", "4.3.2");
        String id = cto51Class.getLessonId();
        treeMap.put("videoId", id);
        treeMap.put("uid", userId);  // "0"是没有登录，"12775616"
        String origType = cto51Class.getOrigType();
        if (origType != null && !"".equals(origType)) {
            treeMap.put("origType", origType);
            if (cto51Class.getModuleId() != null) {
                if ("-1".equals(cto51Class.getModuleId())) {
                    treeMap.put("origType", "4");
                } else {
                    treeMap.put("moduleId", cto51Class.getModuleId());
                }
            }
        } else {
            treeMap.put("origType", "3");
        }
        treeMap.put("videoSign", cto51Md5Sign(id + "eDu_51Cto_siyuanTlw").toLowerCase()); // eDu_51Cto_siyuanTlw 可以用 UUID.randomUUID().toString() 代替
        treeMap.put("time", getCurrentSecond());
        treeMap.put("deviceNumber", deviceNumber); // "84925de3f86f9930|00ee8c7a"); 这个参数可以乱传
        treeMap.put("devices", "1");
        treeMap.put("signNew", signNew(treeMap));  // treeMap.put("signNew", signNew(treeMap)); 这个参数可以乱传
        treeMap.put("sign", cto51Md5Sign(treeMapSortStr(treeMap) + "30A5996A2D60B859"));     // treeMap.put("sign", md5Sign(treeMapSortStr(treeMap) + "30A5996A2D60B859")); 这个参数可以乱传
        String result = HttpUtil.post("https://edu.51cto.com/app.php", treeMap);
        result = UnicodeUtil.toString(result);
        return JSON.parseObject(result, new TypeReference<Cto51Response<Cto51CoursePlayAuth>>(){});
    }

    private static String signNew(TreeMap<String, String> treeMap) {
        String str = treeMapSortStr(treeMap);
        String uid = treeMap.get("uid");

        String m9881 = cto51Md5Sign(cto51Md5Sign(str + cto51Md5Sign("29A30E916D930DFCF2A47E875842FBE0")));
        if (m9881 == null || m9881.length() % 2 == 0) {
            String substring = m9881.substring(0, m9881.length() / 2);
            String substring2 = m9881.substring(m9881.length() / 2);
            return Base64.encode(substring + uid + substring2);
        }
        return "0";
    }


    public static String treeMapSortStr(TreeMap<String, String> treeMap) {
        StringBuilder sb = new StringBuilder();
        Iterator<String> it = treeMap.keySet().iterator();
        while (it.hasNext()) {
            String next = it.next();
            Object object = treeMap.get(next);
            String str = object.toString();
            if (it.hasNext()) {
                sb.append(next);
                sb.append("=");
                sb.append(str);
                sb.append("&");
            } else {
                sb.append(next);
                sb.append("=");
                sb.append(str);
            }
        }
        return sb.toString();
    }

    public static String getCurrentSecond() {
        return String.valueOf(System.currentTimeMillis() / 1000);
    }

    public static void getAppKey() {
        String currentSecond = getCurrentSecond();
        TreeMap treeMap = new TreeMap();
        treeMap.put("do", "index");
        treeMap.put("m", "getAppKey");
        treeMap.put("time", currentSecond);
        treeMap.put("ver", "4.3.2");
        String needSignStr = currentSecond.substring(2, 8);
        treeMap.put("sign", cto51Md5Sign(needSignStr));
        treeMap.put("devices", "Android");
        String result = HttpUtil.post("https://edu.51cto.com/app.php", treeMap);
        System.out.println(result);
    }

    public static String cto51Md5Sign(String needSignStr) {
        char[] cArr = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        byte[] digest = DigestUtil.md5(needSignStr);
        char[] cArr2 = new char[digest.length * 2];
        int i = 0;
        for (byte b : digest) {
            int i2 = i + 1;
            cArr2[i] = cArr[(b >>> 4) & 15];
            i = i2 + 1;
            cArr2[i2] = cArr[b & (byte)15];
        }
        return new String(cArr2);
    }

}